using System;
using System.Diagnostics;
using System.Drawing;
using System.Text.RegularExpressions;

namespace DiggThis.Utils
{
    /// <summary>
    /// Utility class to convert to and from <see cref="Color"/> instances.
    /// </summary>
    public static class ColorUtil
    {
        #region Operations
        /// <summary>
        /// Converts the given <see cref="Color"/> object to a hexadecimal string.
        /// </summary>
        /// <param name="color">The color to convert.</param>
        /// <returns>A string representation of the converted color in the form #000000.</returns>
        public static string ColorToHexString(Color color)
        {
            if (Color.Transparent == color)
                return "Transparent";
            return string.Concat("#", (color.ToArgb() & 0x00FFFFFF).ToString("X6"));
        }
        /// <summary>
        /// Converts a hexadecimal string to a <see cref="Color"/> object.
        /// </summary>
        /// <param name="hexColor">A hex string: "FFFFFF", "#000000"</param>
        public static Color HexStringToColor(string hexColor)
        {
            string hc = ExtractHexDigits(hexColor);
            if (hc.Length != 6)
            {
                throw new ArgumentException("hexColor is not exactly 6 digits.");
            }
            string r = hc.Substring(0, 2);
            string g = hc.Substring(2, 2);
            string b = hc.Substring(4, 2);
            Color color;
            try
            {
                int ri = Int32.Parse(r, System.Globalization.NumberStyles.HexNumber);
                int gi = Int32.Parse(g, System.Globalization.NumberStyles.HexNumber);
                int bi = Int32.Parse(b, System.Globalization.NumberStyles.HexNumber);
                color = Color.FromArgb(ri, gi, bi);
            }
            catch
            {
                throw new ArgumentException("Invalid color specified.");
            }
            return color;
        }
        /// <summary>
        /// Validates the given hexadecimal color string.
        /// </summary>
        /// <param name="hexColor">A hexadecimal string in the form #000000 to validate.</param>
        /// <returns><c>true</c> if the given string is a valid color. Otherwise <c>false</c>.</returns>
        public static bool IsValidColor(string hexColor)
        {
            // Assume the given hex color is invalid.
            bool isValidColor = false;
            try
            {
                // Calling HexStringToColor will throw an exception if it is unable
                // to produce a valid color.
                HexStringToColor(hexColor);
                // Indicate the hex color is valid.
                isValidColor = true;
            }
            catch (Exception ex)
            {
                // Do nothing, we're already defaulting to false.
                Debug.Write(ex.Message);
            }
            // Return the result of the operation.
            return isValidColor;
        }
        #endregion Operations

        #region Helpers
        /// <summary>
        /// Extract only the hex digits from a string.
        /// </summary>
        private static string ExtractHexDigits(string input)
        {
            // Remove any characters that are not digits (like #).
            Regex rx = new Regex("[abcdefABCDEF\\d]+", RegexOptions.Compiled);
            string s = string.Empty;
            foreach (char c in input)
            {
                if (rx.IsMatch(c.ToString()))
                {
                    s += c.ToString();
                }
            }
            return s;
        }
        #endregion Helpers
    }
}
